package com.utry.license.common.verify;

import com.utry.license.common.ExtraLicenseContent;
import com.utry.license.common.LicenseManagerHolder;
import com.utry.license.common.UtryLicenseManager;
import de.schlichtherle.license.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.prefs.Preferences;

/**
 *
 * @description 用于证书管理器初始化以及证书校验
 *
 * @author renxin
 * @email renxinzhiliangzhi@163.com
 * @date 2019/7/25 17:25
 */
@Slf4j
@Component
@EnableScheduling
public class DefaultLicenseVerifier {

    @Value("${spring.application.name}")
    private String subSiteCode;

    @Autowired
    private LicenseConfigBean configBean;

    /**  证书初始化参数 */
    private LicenseParam licenseParam ;

    /**  全局证书管理器 */
    private UtryLicenseManager licenseManager;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired(required = false)
    private CustomLicenseVerifier customLicenseVerifier;
    /**  扩展证书内容 */
    private Map<String,Map<String,String>> customLicenseContent ;

    /**  证书安装标记 */
    private boolean licenseIsInstall;

    /**
     * spring容器启动安装并校验证书
     */
    @PostConstruct
    private void applicationInitLicenseVerify(){
        try {
            // 证书安装
            createLicenseParam();
            licenseManager = LicenseManagerHolder.getUtryLicenseManager(licenseParam);
            licenseManager.install(new File(configBean.getLicensePath()));
            verify();
        }catch (Exception e){

            log.error("应用未正确授权！e:{}",e);
            // spring容器退出
            SpringApplication.exit(applicationContext);
        }
    }

    /**
     * 初始化LicenseParam参数
     *
     * @throws Exception
     */
    private void createLicenseParam(){

        Class<DefaultLicenseVerifier> clazz = DefaultLicenseVerifier.class;
        Preferences preferences = Preferences.userNodeForPackage(clazz);
        // 密钥库密码
        CipherParam cipherParam = new DefaultCipherParam(configBean.getStorePwd());
        KeyStoreParam keyStoreParam
                = new DefaultKeyStoreParam(
                        clazz
                ,configBean.getPublicStorePath()
                ,configBean.getPublicAlias()
                ,configBean.getStorePwd(),null);

        licenseParam = new DefaultLicenseParam(configBean.getSubject(),preferences,keyStoreParam,cipherParam);
    }

    /**
     * 校验证书有效性
     *
     * @return
     * @throws Exception
     */
    private LicenseContent verify() throws Exception{

        // 证书基础数据校验
        LicenseContent licenseContent = licenseManager.cachelessVerify();
        // 扩展数据校验
        ExtraLicenseContent extraLicenseContent = extraVerify(licenseContent);
        customLicenseContent = extraLicenseContent.getCustomContent();
        licenseIsInstall = Boolean.TRUE;
        log.info("证书基础校验规则通过！");
        // 自定义校验逻辑执行,若应用未注入自定义校验逻辑则不执行
        if(customLicenseVerifier != null){
            customLicenseVerifier.customVerify(extraLicenseContent);
            log.info("证书自定义校验通过！");
        }

        return licenseContent;
    }

    /**
     * 证书扩展参数校验
     *
     * @param licenseContent
     * @return
     */
    private ExtraLicenseContent extraVerify(LicenseContent licenseContent) throws Exception{

        ExtraLicenseContent extraContent = (ExtraLicenseContent)licenseContent.getExtra();
        // 取出自定义扩展参数
        customLicenseContent = extraContent.getCustomContent();
        licenseIsInstall = Boolean.TRUE;
        // 子站编码匹配
        boolean subsiteCodeVerify = extraContent.getSubSiteCodeSet().contains(subSiteCode);
        if( ! subsiteCodeVerify){

            throw new LicenseContentException("子站未获授权！");
        }
        // ip地址配置
        boolean ipVerify = false;
        for(String ip : LicenseExtraContentHunter.getIpAddress()){
            if(extraContent.getIpAddressSet().contains(ip)){
                ipVerify = !ipVerify;
                break;
            }
        }
        if( ! ipVerify){

            throw new LicenseContentException("IP地址未获授权！");
        }
        // mac地址配置
        boolean macVerify = false;
        for(String mac : LicenseExtraContentHunter.getMacAddresses()){
            if(extraContent.getMacSet().contains(mac)){
                macVerify = !macVerify;
                break;
            }
        }
        if( ! macVerify){

            throw new LicenseContentException("mac地址未获授权！");
        }

        return extraContent;
    }

    /**
     * 提供获取自定义扩展证书内容的方法,
     *
     * @return
     */
    public Map<String,Map<String,String>> getCustomLicenseContent(){

        if(licenseIsInstall){
            return customLicenseContent;
        }
        log.error("应用证书尚未完成初始安装校验，无法获取到正在退出应用。。。");
        SpringApplication.exit(applicationContext);
        return null;
    }

    /**
     * 定时校验证书有效性方法
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void sheduleVerifyLicense(){

        // 由于容器启动已经安装了证书，这里不再重复安装
        try {
            verify();
            log.info("定时校验证书通过！");
        }catch (Exception e){

            log.error("证书授权失败！e:{}",e);
            SpringApplication.exit(applicationContext);

        }
    }


}
